home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / update / RCS / update.c,v < prev    next >
Encoding:
Text File  |  1992-10-30  |  58.7 KB  |  2,707 lines

  1. head     1.33;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.33
  10. date     92.10.30.14.01.08;  author mottsmth;  state Exp;
  11. branches ;
  12. next     1.32;
  13.  
  14. 1.32
  15. date     92.03.14.16.27.09;  author mottsmth;  state Exp;
  16. branches ;
  17. next     1.31;
  18.  
  19. 1.31
  20. date     92.02.20.21.39.03;  author jhh;  state Exp;
  21. branches ;
  22. next     1.30;
  23.  
  24. 1.30
  25. date     92.01.30.10.52.15;  author jhh;  state Exp;
  26. branches ;
  27. next     1.29;
  28.  
  29. 1.29
  30. date     92.01.27.22.22.40;  author jhh;  state Exp;
  31. branches ;
  32. next     1.28;
  33.  
  34. 1.28
  35. date     91.12.13.11.53.47;  author jhh;  state Exp;
  36. branches ;
  37. next     1.27;
  38.  
  39. 1.27
  40. date     91.11.12.18.57.33;  author rab;  state Exp;
  41. branches ;
  42. next     1.26;
  43.  
  44. 1.26
  45. date     91.11.12.18.54.04;  author rab;  state Exp;
  46. branches ;
  47. next     1.25;
  48.  
  49. 1.25
  50. date     90.08.27.11.32.50;  author shirriff;  state Exp;
  51. branches ;
  52. next     1.24;
  53.  
  54. 1.24
  55. date     90.06.27.13.33.11;  author jhh;  state Exp;
  56. branches ;
  57. next     1.23;
  58.  
  59. 1.23
  60. date     90.02.28.22.12.16;  author jhh;  state Exp;
  61. branches ;
  62. next     1.22;
  63.  
  64. 1.22
  65. date     90.02.28.17.50.09;  author douglis;  state Exp;
  66. branches ;
  67. next     1.21;
  68.  
  69. 1.21
  70. date     90.02.22.18.36.19;  author douglis;  state Exp;
  71. branches ;
  72. next     1.20;
  73.  
  74. 1.20
  75. date     90.02.22.17.39.09;  author jhh;  state Exp;
  76. branches ;
  77. next     1.19;
  78.  
  79. 1.19
  80. date     90.02.15.14.49.43;  author douglis;  state Exp;
  81. branches ;
  82. next     1.18;
  83.  
  84. 1.18
  85. date     90.01.22.09.51.47;  author douglis;  state Exp;
  86. branches ;
  87. next     1.17;
  88.  
  89. 1.17
  90. date     90.01.22.09.45.54;  author douglis;  state Exp;
  91. branches ;
  92. next     1.16;
  93.  
  94. 1.16
  95. date     89.10.02.19.26.25;  author rab;  state Exp;
  96. branches ;
  97. next     1.15;
  98.  
  99. 1.15
  100. date     89.06.19.14.30.42;  author jhh;  state Exp;
  101. branches ;
  102. next     1.14;
  103.  
  104. 1.14
  105. date     89.03.23.15.59.30;  author douglis;  state Exp;
  106. branches ;
  107. next     1.13;
  108.  
  109. 1.13
  110. date     89.02.02.15.57.59;  author brent;  state Exp;
  111. branches ;
  112. next     1.12;
  113.  
  114. 1.12
  115. date     88.12.28.11.31.31;  author ouster;  state Exp;
  116. branches ;
  117. next     1.11;
  118.  
  119. 1.11
  120. date     88.12.28.11.22.04;  author ouster;  state Exp;
  121. branches ;
  122. next     1.10;
  123.  
  124. 1.10
  125. date     88.12.28.11.17.11;  author ouster;  state Exp;
  126. branches ;
  127. next     1.9;
  128.  
  129. 1.9
  130. date     88.12.22.13.50.02;  author brent;  state Exp;
  131. branches ;
  132. next     1.8;
  133.  
  134. 1.8
  135. date     88.08.25.13.24.12;  author ouster;  state Exp;
  136. branches ;
  137. next     1.7;
  138.  
  139. 1.7
  140. date     88.08.23.15.03.01;  author douglis;  state Exp;
  141. branches ;
  142. next     1.6;
  143.  
  144. 1.6
  145. date     88.08.23.14.34.43;  author douglis;  state Exp;
  146. branches ;
  147. next     1.5;
  148.  
  149. 1.5
  150. date     88.08.20.14.26.59;  author ouster;  state Exp;
  151. branches ;
  152. next     1.4;
  153.  
  154. 1.4
  155. date     88.08.20.10.45.24;  author ouster;  state Exp;
  156. branches ;
  157. next     1.3;
  158.  
  159. 1.3
  160. date     88.08.18.14.53.46;  author ouster;  state Exp;
  161. branches ;
  162. next     1.2;
  163.  
  164. 1.2
  165. date     88.08.08.18.39.22;  author ouster;  state Exp;
  166. branches ;
  167. next     1.1;
  168.  
  169. 1.1
  170. date     88.08.08.14.58.29;  author ouster;  state Exp;
  171. branches ;
  172. next     ;
  173.  
  174.  
  175. desc
  176. @@
  177.  
  178.  
  179. 1.33
  180. log
  181. @Add support for both "struct direct" and "struct dirent"
  182. @
  183. text
  184. @/* 
  185.  * update.c --
  186.  *
  187.  *    A smart copy program that preserves date stamps and only
  188.  *    copies if files are out-of-date.
  189.  *
  190.  * Copyright 1988 Regents of the University of California
  191.  * Permission to use, copy, modify, and distribute this
  192.  * software and its documentation for any purpose and without
  193.  * fee is hereby granted, provided that the above copyright
  194.  * notice appear in all copies.  The University of California
  195.  * makes no representations about the suitability of this
  196.  * software for any purpose.  It is provided "as is" without
  197.  * express or implied warranty.
  198.  */
  199.  
  200. #ifndef lint
  201. static char rcsid[] = "$Header: /sprite/src/cmds/update/RCS/update.c,v 1.32 92/03/14 16:27:09 mottsmth Exp Locker: mottsmth $ SPRITE (Berkeley)";
  202. #endif /* not lint */
  203.  
  204. #include <a.out.h>
  205. #include <errno.h>
  206. #include <stdio.h>
  207. #include <stdlib.h>
  208. #include <string.h>
  209. #include <sys/types.h>
  210. #include <sys/dir.h>
  211. #include <sys/file.h>
  212. #include <sys/param.h>
  213. #include <sys/stat.h>
  214. #include <sys/time.h>
  215. #include <limits.h>
  216. #ifdef sprite
  217. #include <fs.h>
  218. #endif
  219. #include <grp.h>
  220. #include <pwd.h>
  221. #include "regexp.h"
  222. #include "option.h"
  223.  
  224. #ifndef HASSTRERROR
  225. char *strerror();
  226. #endif
  227.  
  228. #if (defined(sunos) || defined(OSF1))
  229. #define DirObject struct dirent
  230. #else
  231. #define DirObject struct direct
  232. #endif
  233.  
  234. /*
  235.  * Library imports:
  236.  */
  237.  
  238. extern long lseek();
  239.  
  240. /*
  241.  * Variables and tables used to parse and identify switch values:
  242.  */
  243.  
  244. static int strip = 0;
  245. static int move = 0;
  246. static char *backupDir = (char *)0;
  247. static int backupAge = 14;
  248. static char *modeString = (char *)0;
  249. static int newMode = -1;
  250. static char *ownerName = (char *)0;
  251. static int newOwner = -1;
  252. static int preserveOwnership = 0;
  253. static char *groupName = (char *)0;
  254. static int newGroup = -1;
  255. static int force = 0;
  256. static int noLinks = 0;
  257. static int copyLinks = 1;
  258. static int setTimes = 1;
  259. static int quietMode = 0;
  260. static int verifyMode = 0;
  261. static int niceMode = 0;
  262. static int PruneOpt();
  263. static int ignoreLinks = 0;
  264.  
  265. static Option optionArray[] = {
  266.     {OPT_STRING, "b", (char *) &backupDir,
  267.         "Next argument contains name of backup directory"},
  268.     {OPT_INT, "B", (char *) &backupAge,
  269.         "Next argument contains age (in days) needed to cause backup to overwrite older backup"},
  270.     {OPT_TRUE, "f", (char *) &force,
  271.         "Force: always update, regardless of time stamps"},
  272.     {OPT_STRING, "g", (char *) &groupName,
  273.         "Next argument contains name of group for destination file(s)"},
  274.     {OPT_FALSE, "l", (char *) ©Links,
  275.         "Copy files referenced by symbolic links\n\t\tDefault: copy symbolic links as symbolic links"},
  276.     {OPT_STRING, "m", (char *) &modeString,
  277.         "Next argument contains new protection bits for file(s)"},
  278.     {OPT_TRUE, "M", (char *) &move, "Move instead of copy"},
  279.     {OPT_TRUE, "n", (char *) &niceMode, "Be nice about potential errors"},
  280.     {OPT_STRING, "o", (char *) &ownerName,
  281.         "Next argument contains name of owner for destination file(s)"},
  282.     {OPT_TRUE, "O", (char *) &preserveOwnership,
  283.         "Preserve ownership of files"},
  284.     {OPT_TRUE, "q", (char *) &quietMode,
  285.         "Quiet mode:  only print error messages"},
  286.     {OPT_TRUE, "s", (char *) &strip, "Strip destination (not supported on ds3100/hpux"},
  287.     {OPT_FALSE, "t", (char *) &setTimes, "Use current time for file access times\n\t\tDefault: set target times to match source"},
  288.     {OPT_TRUE, "v", (char *) &verifyMode,
  289.         "Verify mode:  print messages, but don't modify anything"},
  290.     {OPT_FUNC, "p", (char *) PruneOpt,
  291.         "Prune sub-trees defined by given regular expression"}, 
  292.     {OPT_TRUE, "i", (char *) &ignoreLinks,
  293.         "Ignore symbolic links completely"}, 
  294. };
  295.  
  296. /*
  297.  * Miscellaneous global variables:
  298.  */
  299.  
  300. static int realUid;        /* The user id of the caller (which is not
  301.                  * our effective user id, since we're running
  302.                  * setuid. */
  303.  
  304. #define MAX_PRUNE    25
  305. static int prune = 0;        /* Number of regular expressions to prune. */
  306. static struct {
  307.     regexp    *exp;        /* compiled expression */
  308.     char    *expString;    /* expression string */
  309. } pruneArray[MAX_PRUNE]; /* Regular expressions to prune. */
  310.  
  311. #ifdef sprite
  312. #define MAKELINK(x,y,z) Fs_SymLink((x),(y),((z)==S_IFRLNK))
  313. #define MAKEMSG(x) Stat_GetMsg(x)
  314. #define GETATTRS(x,y) Fs_GetAttributes((x),FALSE,(y))
  315. #else
  316. typedef int ReturnStatus;
  317. #define SUCCESS 0
  318. #define MAKELINK(x,y,z) symlink((x),(y))
  319. #define MAKEMSG(x) strerror(x)
  320. #define GETATTRS(x,y) stat((x),(y))
  321. #endif
  322. /*
  323.  * Forward references to procedures declared later in this file:
  324.  */
  325.  
  326. static int Update();
  327. static int UpdateDir();
  328. static int Copy();
  329. static void CheckGroup();
  330. static void PrintUsageAndExit();
  331. static int SetAttributes();
  332. static int CreateDirectory();
  333.  
  334.  
  335. /*
  336.  *----------------------------------------------------------------------
  337.  *
  338.  * main --
  339.  *
  340.  *    Main program for "update".
  341.  *
  342.  * Results:
  343.  *    None.
  344.  *
  345.  * Side effects:
  346.  *    Files get copied, etc.
  347.  *
  348.  *----------------------------------------------------------------------
  349.  */
  350. void
  351. main(argc, argv)
  352.     int argc;
  353.     char *argv[];
  354. {
  355.     char *destFile;
  356.     char *term;
  357.     struct stat srcAttr, destAttr;
  358.     register int argIndex;
  359.     int numErrors = 0;
  360.     char *userName;
  361.  
  362.     /*
  363.      * Suck up command line options and check protection.
  364.      */
  365.  
  366.     argc = Opt_Parse(argc, argv, optionArray, Opt_Number(optionArray),
  367.         OPT_ALLOW_CLUSTERING);
  368. #if (defined(ds3100) || defined(__mips) || defined(hpux))
  369.     if (strip) {
  370.     strip = 0;
  371.     }
  372. #endif
  373.     realUid = getuid();
  374.     if (preserveOwnership ||
  375.     (ownerName != (char *) 0) || (groupName != (char *) 0)) {
  376.     register struct passwd *pwPtr;
  377.  
  378.     pwPtr = getpwuid(realUid);
  379.     if (pwPtr == (struct passwd *) 0) {
  380.         fprintf(stderr,
  381.             "Couldn't find password entry for user %d.\n",
  382.             realUid);
  383.         exit(1);
  384.     }
  385.     userName = malloc((unsigned) (strlen(pwPtr->pw_name) + 1));
  386.     strcpy(userName, pwPtr->pw_name);
  387.     setpwent();
  388.     }
  389.     if (preserveOwnership) {
  390.     if (ownerName != (char *)0) {
  391.         fprintf(stderr, "Ignoring -o option in favor of -O\n");
  392.         ownerName = (char *)0;
  393.     }
  394.     if (groupName != (char *)0) {
  395.         fprintf(stderr, "Ignoring -g option in favor of -O\n");
  396.         groupName = (char *)0;
  397.     }
  398.     /*
  399.      * Don't allow ownership preservation unless:
  400.      *    1. Caller is root -or-
  401.      *    2. Caller is in the wheel group.
  402.      */
  403.     if (realUid != 0) {
  404.         CheckGroup("wheel", userName);
  405.         realUid = 0;
  406.     }
  407.     }
  408.  
  409.     if (ownerName != (char *)0) {
  410.     register struct passwd *pwPtr;
  411.     pwPtr = getpwnam(ownerName);
  412.     if (pwPtr == (struct passwd *)0) {
  413.         fprintf(stderr, "Unknown user \"%s\".\n", ownerName);
  414.         exit(1);
  415.     }
  416.     newOwner = pwPtr->pw_uid;
  417.  
  418.     /*
  419.      * Don't allow a change of owner unless one of three things is true:
  420.      *     1. Caller is root.
  421.      *     2. Target uid is root, and the caller is in the "wheel" group.
  422.      *     3. There's a group name by the same name as the target uid,
  423.      *      and the caller is in the group.
  424.      */
  425.  
  426.     if ((realUid != 0) && (realUid != newOwner)) {
  427.         register struct group *grPtr;
  428.         char *groupName;
  429.         int i;
  430.  
  431.         if (newOwner == 0) {
  432.         groupName = "wheel";
  433.         } else {
  434.         groupName = ownerName;
  435.         }
  436.         CheckGroup(groupName, userName);
  437.     }
  438.     realUid = newOwner;
  439.     }
  440.     if (setuid(realUid) != 0) {
  441.     fprintf(stderr, "Couldn't change user id: %s\n", strerror(errno));
  442.     exit(1);
  443.     }
  444.  
  445.     if (groupName != (char *) 0) {
  446.     register struct group *grPtr;
  447.     grPtr = getgrnam(groupName);
  448.     if (grPtr == (struct group *)0) {
  449.         fprintf(stderr, "Unknown group \"%s\".\n", groupName);
  450.         exit(1);
  451.     }
  452.     newGroup = grPtr->gr_gid;
  453.  
  454.     /*
  455.      * Don't allow a change of group unless either
  456.      *     1. Caller is root.
  457.      *     2. Caller is in the group being changed to.
  458.      */
  459.  
  460.     if (realUid != 0) {
  461.         int i;
  462.  
  463.         for (i = 0; ; i++) {
  464.         if (grPtr->gr_mem[i] == NULL) {
  465.             fprintf(stderr,
  466.                 "Sorry, but you're not in the \"%s\" group.\n",
  467.                 groupName);
  468.             exit(1);
  469.         }
  470.         if (strcmp(grPtr->gr_mem[i], userName) == 0) {
  471.             break;
  472.         }
  473.         }
  474.     }
  475.     endgrent();
  476.     }
  477.     if (modeString != (char *)0) {
  478.     newMode = strtoul(modeString, &term, 8);
  479.     if ((term == modeString) || (*term != 0)) {
  480.         fprintf(stderr, "Bad mode value \"%s\": should be octal integer\n",
  481.             modeString);
  482.         exit(1);
  483.     }
  484.     }
  485.  
  486.     /*
  487.      * Convert backupAge into the date we need in seconds, instead of days
  488.      * prior to the current time.
  489.      */
  490.     if (backupDir && backupAge > 0) {
  491.     backupAge = time(0) - backupAge * 60 * 60 * 24;
  492.     }
  493.     /*
  494.      * Check for a reasonable number of arguments (normally at least 2
  495.      * in addition to the command name).
  496.      */
  497.  
  498.     if (argc < 3) {
  499.     if (argc == 2) {
  500.         destFile = argv[1];
  501.         if ((stat(destFile, &destAttr) == 0)
  502.             && ((destAttr.st_mode & S_IFMT) == S_IFDIR)) {
  503.         /*
  504.          * Exit cleanly if there is a target directory but no
  505.          * sources.  This situation arises occasionally in makefiles.
  506.          */
  507.         fprintf(stderr, "No sources for \"%s\".\n", destFile);
  508.         exit(0);
  509.         }
  510.     }
  511.     PrintUsageAndExit(argv);
  512.     }
  513.  
  514.     /*
  515.      * Determine the initial case.  There are two:
  516.      *     % update {src1 ... srcN} destDir
  517.      *  % update src dest
  518.      *
  519.      * The tricky thing is how to decide when to treat the destination
  520.      * as a directory (and thus put things INSIDE it) and when to treat
  521.      * it as a file (and thus REPLACE it).  We always work in REPLACE
  522.      * mode unless the destination is a directory and either a) there's
  523.      * more than one source or b) the single source isn't a directory.
  524.      */
  525.  
  526.     destFile = argv[argc-1];
  527.     if (stat(destFile, &destAttr) != 0) {
  528.     if (errno == ENOENT) {
  529.         if (argc == 3) {
  530.         /*
  531.          * update src dest - src can be file or directory
  532.          */
  533.         numErrors = Update(argv[1], argv[2]);
  534.         exit(numErrors);
  535.         }
  536.  
  537.         /*
  538.          * Create the destination directory.
  539.          */
  540.  
  541.         if (!quietMode) {
  542.         fprintf(stderr, "Installing: %s\n", destFile);
  543.         }
  544.         if (!verifyMode) {
  545.         if (mkdir(destFile, 0777) != 0) {
  546.             fprintf(stderr,
  547.             "Couldn't create destination directory \"%s\": %s.\n",
  548.             destFile, strerror(errno));
  549.             exit(1);
  550.         }
  551.         if (stat(destFile, &destAttr) != 0) {
  552.             fprintf(stderr,
  553.                 "Couldn't stat \"%s\" after creating it: %s.\n",
  554.                 destFile, strerror(errno));
  555.             exit(1);
  556.         }
  557.         if (SetAttributes(destFile, &destAttr, 0) != 0) {
  558.             exit(1);
  559.         }
  560.         }
  561.  
  562.         /*
  563.          * Fall through to the code to put things inside the
  564.          * destination directory.
  565.          */
  566.         goto putInside;
  567.     }
  568.     fprintf(stderr, "Couldn't access \"%s\": %s.\n", destFile,
  569.         strerror(errno));
  570.     exit(1);
  571.     } else {
  572.     if ((destAttr.st_mode & S_IFMT) == S_IFDIR) {
  573.         if (argc == 3) {
  574.         int result;
  575.         if (copyLinks) {
  576.             result = lstat(argv[1], &srcAttr);
  577.         } else {
  578.             result = stat(argv[1], &srcAttr);
  579.         }
  580.         if (result != 0) {
  581.             fprintf(stderr, "Couldn't access \"%s\": %s.\n", argv[1],
  582.                 strerror(errno));
  583.             exit(1);
  584.         }
  585.         if ((srcAttr.st_mode & S_IFMT) == S_IFDIR) {
  586.             /*
  587.              * Update dir1 dir2
  588.              */
  589.             numErrors = Update(argv[1], argv[2]);
  590.             exit(numErrors);
  591.         }
  592.         }
  593.     } else if (argc == 3) {
  594.         /*
  595.          * Update file1 file2
  596.          */
  597.         numErrors = Update(argv[1], argv[2]);
  598.         exit(numErrors);
  599.     } else {
  600.         PrintUsageAndExit(argv);
  601.     }
  602.     }
  603.  
  604.     /*
  605.      * The above cases handled all the replacements.  At this point there
  606.      * are one or more files to be put INSIDE the destination directory:
  607.      *
  608.      * % update src1 ... srcN destDir
  609.      */
  610.  
  611.     putInside:
  612.  
  613.     for (argIndex = 1; argIndex < argc - 1 ; argIndex++) {
  614.     numErrors += UpdateDir("", argv[argIndex], destFile);
  615.     }
  616.  
  617.     if (numErrors == 0) {
  618.     exit(0);
  619.     }
  620.     exit(1);
  621. }
  622.  
  623. /*
  624.  *----------------------------------------------------------------------
  625.  *
  626.  * PrintUsageAndExit --
  627.  *
  628.  *    Print a usage message and exit the process.
  629.  *
  630.  * Results:
  631.  *    Never returns.
  632.  *
  633.  * Side effects:
  634.  *    Stuff gets printed on stderr.
  635.  *
  636.  *----------------------------------------------------------------------
  637.  */
  638.  
  639. static void
  640. PrintUsageAndExit(argv)
  641.     char *argv[];
  642. {
  643.     fprintf(stderr, "Usage: %s srcFile destFile\n", argv[0]);
  644.     fprintf(stderr, "       %s file1 file2 ... destDir\n", argv[0]);
  645.     Opt_PrintUsage(argv[0], optionArray, Opt_Number(optionArray));
  646.     exit(1);
  647. }
  648.  
  649. /*
  650.  *----------------------------------------------------------------------
  651.  *
  652.  * UpdateDir --
  653.  *
  654.  *    Update a file inside a directory.  This creates the name of the
  655.  *    target file from that of the source file and the destination
  656.  *    directory.  Then Update is called to do the actual updating.
  657.  *
  658.  * Results:
  659.  *    The return value is the number of errors encountered.
  660.  *
  661.  * Side effects:
  662.  *    Files get created or replaced.
  663.  *
  664.  *----------------------------------------------------------------------
  665.  */
  666.  
  667. static int
  668. UpdateDir(srcDir, srcFile, destDir)
  669.     char *srcDir;        /* Directory containing srcFile. */
  670.     char *srcFile;        /* Source file name relative to srcDir. */
  671.     char *destDir;        /* Destination directory name. */
  672. {
  673.     register char *charPtr;
  674.     char newDest[MAXPATHLEN];
  675.     char newSrc[MAXPATHLEN];
  676.  
  677.     /*
  678.      * Set up the source file name.  Append the file to the directory name.
  679.      */
  680.     strcpy(newSrc, srcDir);
  681.     if (*srcDir != '\0') {
  682.     strcat(newSrc, "/");
  683.     }
  684.     strcat(newSrc, srcFile);
  685.  
  686.     /*
  687.      * Set up the destination name.  We take the last component of the
  688.      * filename here.  This handles command lines like
  689.      * % update a/b/c dest
  690.      * which will update dest/c from a/b/c.
  691.      * When we are called recusively srcFile only has one component.
  692.      */
  693.     strcpy(newDest, destDir);
  694.     charPtr = strrchr(srcFile, '/');
  695.     if (charPtr == (char *)NULL) {
  696.     strcat(newDest, "/");
  697.     strcat(newDest, srcFile);
  698.     } else {
  699.     strcat(newDest, charPtr);
  700.     }
  701.     return (Update(newSrc, newDest));
  702. }
  703.  
  704. /*
  705.  *----------------------------------------------------------------------
  706.  *
  707.  * Update --
  708.  *
  709.  *    Update a file.  This checks the date stamps on the destination
  710.  *     file and copies the file data if needed, or just updates the
  711.  *    destination file's attributes, or does nothing if the file
  712.  *    is up-to-date.
  713.  *
  714.  * Results:
  715.  *    The return value is the number of errors encountered.
  716.  *
  717.  * Side effects:
  718.  *    None.
  719.  *
  720.  *----------------------------------------------------------------------
  721.  */
  722.  
  723. static int
  724. Update(srcFile, destFile)
  725.     char *srcFile;        /* Name of source file. */
  726.     char *destFile;        /* Name of file that should be made
  727.                  * identical to source file. */
  728. {
  729.     int result;    
  730.     struct stat srcAttr, destAttr, backupAttr;
  731.     char *lastSlash;
  732.     char tmpFileName[MAXPATHLEN];
  733.     static char *typeNames[] = {
  734.     "0",            "010000",        "character special",
  735.     "030000",        "directory",        "050000",
  736.     "block special",    "070000",        "regular file",
  737.     "0110000",        "symbolic link",    "0130000",
  738.     "socket",        "pseudo-device",    "remote link",
  739.     "0170000"
  740.     };
  741.     int backup;
  742.     int    i;
  743.  
  744.     if (prune) {
  745.     lastSlash = strrchr(srcFile, '/');
  746.     if (lastSlash == NULL) {
  747.         lastSlash = srcFile;
  748.     } else {
  749.         lastSlash += 1;
  750.     }
  751.     for (i = 0; i < prune; i++) {
  752.         if (regexec(pruneArray[i].exp, lastSlash)) {
  753.         if (!quietMode) {
  754.             fprintf(stderr, "Pruning:    %s { %s }\n", destFile,
  755.             pruneArray[i].expString);
  756.         }
  757.         return 0;
  758.         }
  759.     }
  760.     }
  761.     if (copyLinks || ignoreLinks) {
  762.     result = lstat(srcFile, &srcAttr);
  763.     } else {
  764.     result = stat(srcFile, &srcAttr);
  765.     }
  766.     if (result != 0) {
  767.     fprintf(stderr, "Couldn't find \"%s\": %s.\n",
  768.         srcFile, strerror(errno));
  769.     return 1;
  770.     }
  771.  
  772.     if (((srcAttr.st_mode & S_IFMT) == S_IFLNK) && ignoreLinks) {
  773.     if (!quietMode) {
  774.         fprintf(stderr, "Ignoring link: %s\n", srcFile);
  775.     }
  776.     return 0;
  777.     }
  778.  
  779.     if ((lstat(destFile, &destAttr) != 0) && (errno = ENOENT)) {
  780.     /*
  781.      * OK to create new file.
  782.      */
  783.     if ((srcAttr.st_mode & S_IFMT) != S_IFDIR) {
  784.         if (!quietMode) {
  785.         fprintf(stderr, "Installing: %s\n", destFile);
  786.         }
  787.         if (verifyMode) {
  788.         return 0;
  789.         }
  790.         return Copy(srcFile, &srcAttr, destFile, 0);
  791.     } else {
  792.         /*
  793.          * Make the target directory and then fall through to
  794.          * the code below which recursively updates it.
  795.          */
  796.         if (!quietMode) {
  797.         fprintf(stderr, "Installing: %s\n", destFile);
  798.         }
  799.         if (!verifyMode) {
  800.         if (mkdir(destFile, (int) (srcAttr.st_mode & 0777)) != 0) {
  801.             fprintf(stderr, "Couldn't create directory \"%s\": %s.\n",
  802.                 destFile, strerror(errno));
  803.             return 1;
  804.         }
  805.         if (SetAttributes(destFile, &srcAttr, 0) != 0) {
  806.             return(1);
  807.         }
  808.         }
  809.         destAttr = srcAttr;
  810.     }
  811.     }
  812.     if ((destAttr.st_mode & S_IFMT) != (srcAttr.st_mode & S_IFMT)) {
  813.     fprintf(stderr,  "Type of \"%s\" (%s) differs from \"%s\" (%s).\n",
  814.         srcFile, typeNames[(srcAttr.st_mode & S_IFMT) >> 12],
  815.         destFile, typeNames[(destAttr.st_mode & S_IFMT) >> 12]);
  816.  
  817.     if (niceMode) {
  818.         return 0;
  819.     }
  820.     /*
  821.      * Don't let the user get confused by failing to copy a link to a link
  822.      * because of type mismatch.  This may easily happen if something
  823.      * is installed as a link and then later the "copyLinks" flag is
  824.      * disabled.
  825.      */
  826.     if (!copyLinks && ((destAttr.st_mode & S_IFMT) == S_IFLNK) &&
  827.         ((srcAttr.st_mode & S_IFMT) == S_IFREG)) {
  828.         if (lstat(srcFile, &srcAttr) == 0 &&
  829.         ((srcAttr.st_mode & S_IFMT) == S_IFLNK)) {
  830.         fprintf(stderr, "\tNote: following a link to a regular file due to \"-l\" option.\n");
  831.         }
  832.     }
  833.     return(1);
  834.     }
  835.     if ((srcAttr.st_mode & S_IFMT) == S_IFDIR) {
  836.     DIR *dirStream;
  837.     DirObject *dirEntryPtr;
  838.     int numErrors = 0;
  839.  
  840.     /*
  841.      * See if we can just rename the directory.
  842.      */
  843.  
  844.     if (move && !verifyMode && !strip) {
  845.         if (rename(srcFile, destFile) == 0) {
  846.         return 0;
  847.         }
  848.     }
  849.  
  850.     /*
  851.      * Recursively update the target directory, which already exists.
  852.      *    Read all names from srcFile directory, and call
  853.      *    UpdateDir(eachName, destFile) to update each one.
  854.      */
  855.  
  856.     dirStream = opendir(srcFile);
  857.     if (dirStream == (DIR *)NULL) {
  858.         fprintf(stderr, "Can't read source directory \"%s\".\n",
  859.                 srcFile);
  860.         return(1);
  861.     }
  862.     dirEntryPtr = readdir(dirStream);
  863.     while (dirEntryPtr != (DirObject *)NULL) {
  864.         if ((dirEntryPtr->d_namlen == 1 &&
  865.          dirEntryPtr->d_name[0] == '.') ||
  866.         (dirEntryPtr->d_namlen == 2 &&
  867.          dirEntryPtr->d_name[0] == '.' &&
  868.          dirEntryPtr->d_name[1] == '.')) {
  869.         /* Don't do "." or ".." */ ;
  870.         } else {
  871.         numErrors += UpdateDir(srcFile, dirEntryPtr->d_name,
  872.             destFile);
  873.         }
  874.         dirEntryPtr = readdir(dirStream);
  875.     }
  876.     closedir(dirStream);
  877.  
  878.     /*
  879.      * If moving, must delete source directory.
  880.      */
  881.  
  882.     if (move && !verifyMode && (rmdir(srcFile) != 0)) {
  883.         fprintf(stderr,
  884.             "Couldn't remove directory \"%s\" during move: %s\n",
  885.             srcFile, strerror(errno));
  886.         numErrors++;
  887.     }
  888.     return(numErrors);
  889.      }
  890.      if (force || (destAttr.st_mtime < srcAttr.st_mtime)) {
  891.     /*
  892.      * Target file has to be updated.
  893.      */
  894.  
  895.     if (!quietMode) {
  896.         fprintf(stderr, "Updating: %s\n", destFile);
  897.     }
  898.     if (verifyMode) {
  899.         return 0;
  900.     }
  901.  
  902.     /*
  903.      * If no backup directory, then rename the file, copy a new
  904.      * version in, and remove the old renamed target.
  905.      */
  906.  
  907.     if (backupDir == (char *) 0) {
  908.         sprintf(tmpFileName, "%sXXX", destFile);
  909.  
  910.         if (rename(destFile, tmpFileName) != 0) {
  911.         fprintf(stderr, "Couldn't rename \"%s\" to \"%s\": %s.\n",
  912.             destFile, tmpFileName, strerror(errno));
  913.         return(1);
  914.         }
  915.         if (Copy(srcFile, &srcAttr, destFile, 0) == 0) {
  916.         if (unlink(tmpFileName) != 0) {
  917.             fprintf(stderr,
  918.                 "Couldn't remove renamed old version \"%s\": %s.\n",
  919.                 tmpFileName, strerror(errno));
  920.             return 1;
  921.         }
  922.         } else {
  923.         if (rename(tmpFileName, destFile) != 0) {
  924.             fprintf(stderr,
  925.             "Couldn't restore original \"%s\":  see \"%s\".\n",
  926.             destFile, tmpFileName);
  927.         }
  928.         return 1;
  929.         }
  930.         return 0;
  931.     }
  932.  
  933.     /*
  934.      * There's a backup directory.  Copy the file to it, then
  935.      * copy in new version.
  936.      */
  937.  
  938.     lastSlash = strrchr(destFile, '/');
  939.     if (lastSlash == NULL) {
  940.         lastSlash = destFile;
  941.     } else {
  942.         lastSlash += 1;
  943.     }
  944.     sprintf(tmpFileName, "%s/%s", backupDir, lastSlash);
  945.  
  946.     backup = 1;
  947.     if (backupAge > 0 && stat(tmpFileName, &backupAttr) == 0) {
  948.  
  949.         if (destAttr.st_mtime > backupAge) {
  950.         if (!quietMode) {
  951.             fprintf(stderr,
  952.                 "\tWarning: target too recent, so not overwriting backup copy.\n");
  953.         }
  954.         backup = 0;
  955.         }
  956.     }
  957.     if (backup && Copy(destFile, &destAttr, tmpFileName, 1) != 0) {
  958.         fprintf(stderr,
  959.             "Couldn't copy \"%s\" to backup dir \"%s\".\n",
  960.             destFile, backupDir);
  961.         return 1;
  962.     }
  963.     unlink(destFile);
  964.     return Copy(srcFile, &srcAttr, destFile, 0);
  965.     }
  966.     return 0;
  967. }
  968.  
  969. /*
  970.  *----------------------------------------------------------------------
  971.  *
  972.  * Copy --
  973.  *
  974.  *    Copy a file.  For regular files this copies the file data.
  975.  *    For other special files a new file of the same type as
  976.  *    the original is created.
  977.  *
  978.  * Results:
  979.  *    0 is returned if all went well, and 1 is returned if an
  980.  *    error occurred.
  981.  *
  982.  * Side effects:
  983.  *    srcFile gets copied to destFile.
  984.  *
  985.  *----------------------------------------------------------------------
  986.  */
  987.  
  988. static int
  989. Copy(srcFile, srcAttrPtr, destFile, backup)
  990.     char *srcFile;            /* Name of source file. */
  991.     struct stat *srcAttrPtr;        /* Attributes of source file (used to
  992.                      * save stat calls). */
  993.     char *destFile;            /* Name of destination file. */
  994.     int backup;                /* Non-zero means this is a backup
  995.                      * copy being made;  as a result,
  996.                      * attribute changes are handled
  997.                      * differently. */
  998. {
  999. #define BUFSIZE 8192
  1000.     static char buffer[BUFSIZE];
  1001.  
  1002.     /*
  1003.      * See if we can just rename the file.
  1004.      */
  1005.     if (move && (realUid == srcAttrPtr->st_uid) && !strip) {
  1006.     if (rename(srcFile, destFile) == 0) {
  1007.         return 0;
  1008.     }
  1009.     }
  1010.  
  1011.     switch (srcAttrPtr->st_mode & S_IFMT) {
  1012.     case S_IFREG: {
  1013.         int result = 0;
  1014.         int amountRead, bytesCopied;
  1015.         int maxSize = INT_MAX;
  1016.         int srcID, destID;
  1017.         int stripping = 0;
  1018.  
  1019.         srcID = open(srcFile, O_RDONLY, 0); 
  1020.         if (srcID < 0) {
  1021.         fprintf(stderr, "Couldn't open \"%s\": %s.\n",
  1022.             srcFile, strerror(errno));
  1023.         return 1;
  1024.         }
  1025.         (void) unlink(destFile);
  1026.         destID = open(destFile, O_WRONLY|O_CREAT|O_TRUNC,
  1027.             srcAttrPtr->st_mode & 0777);
  1028.         if (destID < 0) {
  1029.         char pathname[MAXPATHLEN];
  1030.         char *s;
  1031.         int realErrno;
  1032.  
  1033.         /*
  1034.          * Some of the subdirectories in the path may
  1035.          * not exist.  Try and create them, and if
  1036.          * successful, try to open the file again.  Make sure
  1037.          * that if we don't successfully create subdirectories and
  1038.          * then redo the open, we return the errno corresponding
  1039.          * to the open, not the failed mkdir.
  1040.          */
  1041.  
  1042.         realErrno = errno;
  1043.         strcpy(pathname, destFile);
  1044.         if ((s = strrchr(pathname, '/')) != NULL) {
  1045.             *s = '\0';
  1046.             if (CreateDirectory(pathname) == 0) {
  1047.             destID = open(destFile, O_WRONLY|O_CREAT|O_TRUNC,
  1048.                 srcAttrPtr->st_mode & 0777);
  1049.             } else {
  1050.             errno = realErrno;
  1051.             }
  1052.         }
  1053.         if (destID < 0) {
  1054.             fprintf(stderr, "Couldn't create \"%s\": %s.\n",
  1055.             destFile, strerror(errno));
  1056.             return 1;
  1057.         }
  1058.         }
  1059. #if (!defined(ds3100) && !defined(__mips) && !defined(hpux))
  1060.         if (strip) {
  1061.         struct exec hdr;
  1062.         if ((read(srcID, (char *) &hdr, sizeof(hdr)) != sizeof(hdr))
  1063.             || N_BADMAG(hdr)) {
  1064.             fprintf(stderr,
  1065.                 "\"%s\" isn't a binary executable;  can't strip.\n",
  1066.                 srcFile);
  1067.         } else {
  1068.             maxSize = N_TXTOFF(hdr) + hdr.a_text + hdr.a_data;
  1069.             stripping = 1;
  1070.         }
  1071.         lseek(srcID, (long) 0, L_SET);
  1072.         }
  1073. #endif
  1074.  
  1075.         for (bytesCopied = 0; bytesCopied < maxSize;
  1076.             bytesCopied += amountRead) {
  1077.         int wanted;
  1078.  
  1079.         wanted = maxSize - bytesCopied;
  1080.         if (wanted > BUFSIZE) {
  1081.             wanted = BUFSIZE;
  1082.         }
  1083.         amountRead = read(srcID, buffer, wanted);
  1084.         if (amountRead < 0) {
  1085.             fprintf(stderr, "Read error on \"%s\": %s.\n",
  1086.                 srcFile, strerror(errno));
  1087.             result = 1;
  1088.             break;
  1089.         }
  1090.         if (amountRead == 0) {
  1091.             break;
  1092.         }
  1093.  
  1094. #if (!defined(ds3100) && !defined(__mips) && !defined(hpux))
  1095.         /*
  1096.          * If we're stripping, clear out the symbol table size
  1097.          * in the file's header.
  1098.          */
  1099.  
  1100.         if ((bytesCopied == 0) && stripping) {
  1101.             struct exec *execPtr = (struct exec *) buffer;
  1102.  
  1103.             execPtr->a_syms = 0;
  1104.             execPtr->a_trsize = 0;
  1105.             execPtr->a_drsize = 0;
  1106.         }
  1107. #endif
  1108.         if (write(destID, buffer, amountRead) != amountRead) {
  1109.             fprintf(stderr, "Write error on \"%s\": %s.\n",
  1110.                 destFile, strerror(errno));
  1111.             result = 1;
  1112.             break;
  1113.         }
  1114.         }
  1115.         close(srcID);
  1116.         close(destID);
  1117.         if (result != 0) {
  1118.         return result;
  1119.         }
  1120.         break;
  1121.     }
  1122.     case S_IFDIR: {
  1123.         fprintf(stderr, "Internal error:  Copy called with directory.\n");
  1124.         return 1;
  1125.     }
  1126.     case S_IFLNK:
  1127. #ifdef sprite
  1128.     case S_IFRLNK:
  1129. #endif
  1130.         {
  1131.         char targetName[MAXPATHLEN];
  1132.         int length;
  1133.         ReturnStatus    status;
  1134.  
  1135.         length = readlink(srcFile, targetName, MAXPATHLEN);
  1136.         if (length < 0) {
  1137.         fprintf(stderr, "Couldn't read value of link \"%s\": %s.\n",
  1138.             srcFile, strerror(errno));
  1139.         return 1;
  1140.         }
  1141.         targetName[length] = 0;
  1142.         status = MAKELINK(targetName, destFile, 
  1143.                   (srcAttrPtr->st_mode & S_IFMT));
  1144.         if (status != SUCCESS) {
  1145.         char pathname[MAXPATHLEN];
  1146.         char *s;
  1147.         int realStatus;
  1148.  
  1149.         /*
  1150.          * Some of the subdirectories in the path may
  1151.          * not exist.  Try and create them, and if
  1152.          * successful, try to open the file again.  Make sure
  1153.          * that if we don't successfully create subdirectories and
  1154.          * then redo the open, we return the errno corresponding
  1155.          * to the open, not the failed mkdir.
  1156.          */
  1157.  
  1158.         realStatus = status;
  1159.         strcpy(pathname, destFile);
  1160.         if ((s = strrchr(pathname, '/')) != NULL) {
  1161.             *s = '\0';
  1162.             if (CreateDirectory(pathname) == 0) {
  1163.             status = MAKELINK(targetName, destFile, 
  1164.                 (srcAttrPtr->st_mode & S_IFMT));
  1165.             } else {
  1166.             status = realStatus;
  1167.             }
  1168.         }
  1169.         if (status != SUCCESS) {
  1170.             fprintf(stderr,
  1171.                 "Couldn't create link at \"%s\": %s.\n",
  1172.                 destFile, MAKEMSG(status));
  1173.             return 1;
  1174.         }
  1175.         }
  1176.         break;
  1177.     }
  1178.     case S_IFBLK:
  1179.     case S_IFCHR: {
  1180.         ReturnStatus    status;
  1181. #ifdef sprite
  1182.         Fs_Attributes     attrs;
  1183.         Fs_Device        device;
  1184. #else
  1185.         struct stat attrs;
  1186. #endif
  1187.  
  1188.         status = GETATTRS(srcFile, &attrs);
  1189.         if (status != SUCCESS) {
  1190.         fprintf(stderr, "Unable to get attributes of \"%s\": %s\n",
  1191.             srcFile, MAKEMSG(status));
  1192.         return 1;
  1193.         }
  1194. #ifdef sprite
  1195.         device.type = attrs.devType;
  1196.         device.unit = attrs.devUnit;
  1197.         device.serverID = attrs.devServerID;
  1198.         device.data = (ClientData) 0;
  1199.         status = Fs_MakeDevice(destFile, &device, 
  1200.                    srcAttrPtr->st_mode & 0777);
  1201. #else
  1202.         status = mknod(destFile, srcAttrPtr->st_mode,
  1203.                srcAttrPtr->st_dev);
  1204. #endif
  1205.         if (status != SUCCESS) {
  1206.         fprintf(stderr, "Unable to create device \"%s\": %s\n",
  1207.             destFile, MAKEMSG(status));
  1208.         return 1;
  1209.         }
  1210.         break;
  1211.     }
  1212.     case S_IFIFO: {
  1213.         fprintf(stderr, "\"%s\" is a fifo; don't know how to update.\n",
  1214.             srcFile);
  1215.         return 1;
  1216.     }
  1217. #ifdef sprite
  1218.     case S_IFPDEV: {
  1219.         fprintf(stderr,
  1220.             "\"%s\" is a pseudo-device; don't know how to update.\n",
  1221.             srcFile);
  1222.         return 1;
  1223.     }
  1224. #endif
  1225.     default: {
  1226.         fprintf(stderr,
  1227.             "\"%s\" has type 0x%x; don't know how to update.\n",
  1228.             srcFile, srcAttrPtr->st_mode & S_IFMT);
  1229.         return 1;
  1230.     }
  1231.     }
  1232.     if (SetAttributes(destFile, srcAttrPtr, backup) != 0) {
  1233.     return 1;
  1234.     }
  1235.     if (move) {
  1236.     if (unlink(srcFile) != 0) {
  1237.         fprintf(stderr,
  1238.             "Couldn't remove source file \"%s\" during move: %s.\n",
  1239.             srcFile, strerror(errno));
  1240.         return 1;
  1241.     }
  1242.     }
  1243.     return 0;
  1244. }
  1245.  
  1246. /*
  1247.  *----------------------------------------------------------------------
  1248.  *
  1249.  * CheckGroup --
  1250.  *
  1251.  *    Verify that a user is in a particular group.  This is called to
  1252.  *    check against the wrong users attempting to use update to
  1253.  *    change file ownership.
  1254.  *
  1255.  * Results:
  1256.  *    Returns if the user is ok, otherwise this exits.
  1257.  *
  1258.  * Side effects:
  1259.  *    Suicide if the user isn't in the group.
  1260.  *
  1261.  *----------------------------------------------------------------------
  1262.  */
  1263.  
  1264. static void
  1265. CheckGroup(groupName, userName)
  1266.     char *groupName;        /* group name */
  1267.     char *userName;        /* user name */
  1268. {
  1269.     register struct group *grPtr;
  1270.     int i;
  1271.  
  1272.     grPtr = getgrnam(groupName);
  1273.     if (grPtr == (struct group *) 0) {
  1274.     fprintf(stderr, "Couldn't find \"%s\" group to check owner change.\n",
  1275.         groupName);
  1276.     exit(1);
  1277.     }
  1278.     for (i = 0; ; i++) {
  1279.     if (grPtr->gr_mem[i] == NULL) {
  1280.         fprintf(stderr,
  1281.             "Can't change owners: you're not in the \"%s\" group.\n",
  1282.             groupName);
  1283.         exit(1);
  1284.     }
  1285.     if (strcmp(grPtr->gr_mem[i], userName) == 0) {
  1286.         break;
  1287.     }
  1288.     }
  1289.     endgrent();
  1290.     return;
  1291. }
  1292.  
  1293. /*
  1294.  *----------------------------------------------------------------------
  1295.  *
  1296.  * SetAttributes --
  1297.  *
  1298.  *    Set attributes of target file, taking into account command line
  1299.  *    options that specify group and new mode.
  1300.  *
  1301.  * Results:
  1302.  *    Returns 0 if all went well, 1 if there was an error.
  1303.  *
  1304.  * Side effects:
  1305.  *    Times, protection, and group may get changed for fileName.
  1306.  *
  1307.  *----------------------------------------------------------------------
  1308.  */
  1309.  
  1310. static int
  1311. SetAttributes(fileName, attrPtr, backup)
  1312.     char *fileName;            /* Name of file to change. */
  1313.     struct stat *attrPtr;        /* Attributes of source file, which
  1314.                      * are used (along with command-line
  1315.                      * options) to set fileName. */
  1316.     int backup;                /* Non-zero means that this is a
  1317.                      * backup copy whose attributes are
  1318.                      * being set;  ignore command-line
  1319.                      * options and just copy relevant
  1320.                      * attributes from the source. */
  1321.  
  1322. {
  1323. #ifdef SYSV
  1324.     struct utimbuf times;
  1325. #else
  1326.     struct timeval times[2];
  1327. #endif
  1328.  
  1329.     /*
  1330.      * Preserve ownership if requested (or if this is a backup copy).
  1331.      */
  1332.  
  1333.     if (preserveOwnership && !backup) {
  1334.     if (chown(fileName, attrPtr->st_uid, attrPtr->st_gid) != 0) {
  1335.         fprintf(stderr, "Couldn't set owner for \"%s\": %s.\n",
  1336.             fileName, strerror(errno));
  1337.         return 1;
  1338.     }
  1339.     }
  1340.  
  1341.     /*
  1342.      * Set group if a specific one was requested.
  1343.      */
  1344.  
  1345.     if ((newGroup >= 0) && !backup) {
  1346.     if (chown(fileName, -1, newGroup) != 0) {
  1347.         fprintf(stderr, "Couldn't set group id for \"%s\": %s.\n",
  1348.             fileName, strerror(errno));
  1349.         return 1;
  1350.     }
  1351.     }
  1352.  
  1353.     /*
  1354.      * Don't set permissions or times for symbolic links, since they'll
  1355.      * end up affecting the target of the link.
  1356.      */
  1357.  
  1358.     if ((attrPtr->st_mode & S_IFMT) == S_IFLNK) {
  1359.     return 0;
  1360.     }
  1361.  
  1362.     /*
  1363.      * Set permissions (but only if the source isn't a symbolic link;  if
  1364.      * it's a link, then we'd be setting the permissions of the link's
  1365.      * target).
  1366.      */
  1367.  
  1368.     if ((newMode >= 0) && !backup) {
  1369.     if (chmod(fileName, newMode) != 0) {
  1370.         fprintf(stderr,
  1371.             "Couldn't set permissions of \"%s\" to 0%o: %s.\n",
  1372.             fileName, newMode, strerror(errno));
  1373.         return 1;
  1374.     }
  1375.     } else {
  1376.     /* 
  1377.      * Set the file permissions.  When the file was created the
  1378.      * permissions were modified by umask, so we have to set them
  1379.      * here.
  1380.      */
  1381.     if (chmod(fileName, attrPtr->st_mode & 0777) != 0) {
  1382.         fprintf(stderr,
  1383.             "Couldn't set permissions for \"%s\": %s.\n",
  1384.             fileName, strerror(errno));
  1385.         return 1;
  1386.     }
  1387.     /*
  1388.      * Preserve the set-user-id bit if a new mode wasn't given, and if
  1389.      * the set-user-id bit was set in the source file, and if the file's
  1390.      * new owner is the same as its previous owner.
  1391.      */
  1392.     
  1393.     if ((attrPtr->st_mode & (S_ISUID)) &&
  1394.         (preserveOwnership || (realUid == attrPtr->st_uid))) {
  1395.         if (chmod(fileName, attrPtr->st_mode & 04777) != 0) {
  1396.         fprintf(stderr,
  1397.             "Couldn't set set-user-id for \"%s\": %s.\n",
  1398.             fileName, strerror(errno));
  1399.         return 1;
  1400.         }
  1401.     }
  1402.     }
  1403.  
  1404.     /*
  1405.      * Set times.
  1406.      */
  1407.  
  1408.     if ((setTimes) || backup) {
  1409. #ifdef SYSV
  1410.     times.actime = attrPtr->st_atime;
  1411.     times.modtime = attrPtr->st_mtime;
  1412.     if (utime(fileName, ×) != 0) {
  1413. #else
  1414.     times[0].tv_usec = times[1].tv_usec = 0;
  1415.     times[0].tv_sec = attrPtr->st_atime;
  1416.     times[1].tv_sec = attrPtr->st_mtime;
  1417.     if (utimes(fileName, times) != 0) {        
  1418. #endif
  1419.         fprintf(stderr, "Couldn't set times of \"%s\": %s.\n",
  1420.             fileName, strerror(errno));
  1421.         return 1;
  1422.     }
  1423.     }
  1424.  
  1425. #ifdef sprite
  1426.     /*
  1427.      * Set the advisory file type if it's set in the source file.
  1428.      */
  1429.     if (attrPtr->st_userType != S_TYPE_UNDEFINED) {
  1430.     if (setfiletype(fileName, attrPtr->st_userType) != 0) {
  1431.         fprintf(stderr, "Couldn't set type of \"%s\": %s.\n",
  1432.             fileName, strerror(errno));
  1433.     }
  1434.     }
  1435. #endif
  1436.  
  1437.     return 0;
  1438. }
  1439.  
  1440. static int
  1441. CreateDirectory(dir)
  1442.     char *dir;
  1443. {
  1444.     char pathname[MAXPATHLEN];
  1445.     char *s;
  1446.  
  1447.     /*
  1448.      * Try to create the directory
  1449.      */
  1450.     if (mkdir(dir, 0777) == 0) {
  1451.     return 0;
  1452.     }
  1453.  
  1454.     /*
  1455.      * Couldn't create the directory.
  1456.      * Try to create the parent directory, and then try again.
  1457.      */
  1458.     strcpy(pathname, dir);
  1459.     if ((s = strrchr(pathname, '/')) == NULL) {
  1460.     return 1;
  1461.     }
  1462.     *s = '\0';
  1463.     if (CreateDirectory(pathname) == 0) {
  1464.     return mkdir(dir, 0777);
  1465.     }
  1466.     return 1;
  1467. }
  1468.  
  1469. /*
  1470.  *----------------------------------------------------------------------
  1471.  *
  1472.  * PruneOpt --
  1473.  *
  1474.  *    Process a "-p" option.  Take the regular expression that follows
  1475.  *    and put it in the array of trees to prune..
  1476.  *
  1477.  * Results:
  1478.  *    1 (-p option requires an argument).
  1479.  *
  1480.  * Side effects:
  1481.  *    The argument to the option is put in the regular expression array..
  1482.  *
  1483.  *----------------------------------------------------------------------
  1484.  */
  1485.  
  1486. static int
  1487. PruneOpt(optionPtr, exprString)
  1488.     char    *optionPtr;     /* Current option. */
  1489.     char    *exprString;    /* The regular expression. */
  1490. {
  1491.     regexp    *expPtr;
  1492.  
  1493.     if ((exprString == NULL) || (*exprString == '-')) {
  1494.     fprintf(stderr, "Warning: \"-%s\" option needs an argument\n", 
  1495.         optionPtr);
  1496.     return 1;
  1497.     }
  1498.     expPtr = regcomp(exprString);
  1499.     if (expPtr == NULL) {
  1500.     fprintf(stderr, "Warning: \"%s\" is not a regular expression.\n", 
  1501.         exprString);
  1502.     return 1;
  1503.     }
  1504.     if (prune >= MAX_PRUNE) {
  1505.     fprintf(stderr, "Warning: too many prune options.\n");
  1506.     return 1;
  1507.     }
  1508.     pruneArray[prune].exp = expPtr;
  1509.     pruneArray[prune].expString = exprString;
  1510.     prune++;
  1511.     return 1;
  1512. }
  1513.  
  1514. /*
  1515.  *----------------------------------------------------------------------
  1516.  *
  1517.  * regerror --
  1518.  *
  1519.  *    This routine is called by the regular expression library when
  1520.  *    something goes wrong.
  1521.  *
  1522.  * Results:
  1523.  *    None.
  1524.  *
  1525.  * Side effects:
  1526.  *    Stuff is printed out.
  1527.  *
  1528.  *----------------------------------------------------------------------
  1529.  */
  1530.  
  1531. void
  1532. regerror(msg)
  1533.     char    *msg;    /* The error message. */
  1534. {
  1535.     fprintf(stderr, "Error in regular expression library: %s\n", msg);
  1536.     exit(1);
  1537. }
  1538.  
  1539.  
  1540. #ifdef NEEDSTRERROR
  1541.  
  1542. /*
  1543.  *----------------------------------------------------------------------
  1544.  *
  1545.  * strerror --
  1546.  *
  1547.  *      Simplistic message generator for systems that
  1548.  *    don't have the real thing.
  1549.  *
  1550.  * Results:
  1551.  *    None.
  1552.  *
  1553.  * Side effects:
  1554.  *    None.
  1555.  *
  1556.  *----------------------------------------------------------------------
  1557.  */
  1558.  
  1559. char *
  1560. strerror(error)
  1561.     int error;
  1562. {
  1563.     extern char *sys_errlist[];
  1564.     extern int sys_nerr;
  1565.     static char badMsg[100];
  1566.  
  1567.     if (error > sys_nerr) {
  1568.     sprintf(badMsg, "Unknown errno value: %d\n", error);
  1569.     return badMsg;
  1570.     } else {
  1571.     return sys_errlist[error];
  1572.     }
  1573. }
  1574.  
  1575. #endif
  1576. @
  1577.  
  1578.  
  1579. 1.32
  1580. log
  1581. @Add ifdefs and macros to make update portable.
  1582. @
  1583. text
  1584. @d18 1
  1585. a18 1
  1586. static char rcsid[] = "$Header: /sprite/src/cmds/update/RCS/update.c,v 1.29 92/01/27 22:22:40 jhh Exp $ SPRITE (Berkeley)";
  1587. a22 2
  1588. #include <grp.h>
  1589. #include <pwd.h>
  1590. d36 2
  1591. d45 6
  1592. d654 1
  1593. a654 1
  1594.     struct direct *dirEntryPtr;
  1595. d680 1
  1596. a680 1
  1597.     while (dirEntryPtr != (struct direct *)NULL) {
  1598. d693 1
  1599. @
  1600.  
  1601.  
  1602. 1.31
  1603. log
  1604. @changed a printf
  1605. @
  1606. text
  1607. @d18 1
  1608. a18 1
  1609. static char rcsid[] = "$Header: /sprite/src/cmds/update/RCS/update.c,v 1.30 92/01/30 10:52:15 jhh Exp Locker: jhh $ SPRITE (Berkeley)";
  1610. a23 1
  1611. #include <option.h>
  1612. d34 2
  1613. d37 7
  1614. a43 1
  1615. #include <regexp.h>
  1616. d74 1
  1617. d97 1
  1618. a97 1
  1619.     {OPT_TRUE, "s", (char *) &strip, "Strip destination (not supported on ds3100"},
  1620. d103 2
  1621. d122 11
  1622. d151 1
  1623. a151 1
  1624.  *    Main program for "udpate".
  1625. d179 1
  1626. a179 1
  1627. #ifdef ds3100
  1628. d251 1
  1629. a251 1
  1630.     if (setreuid(realUid, realUid) != 0) {
  1631. d572 1
  1632. a572 1
  1633.     if (copyLinks) {
  1634. d583 7
  1635. d611 2
  1636. a612 29
  1637.         result = mkdir(destFile, (int) (srcAttr.st_mode & 0777));
  1638.         if (result != 0) {
  1639.             char pathname[MAXPATHLEN];
  1640.             char *s;
  1641.             int realErrno;
  1642.             /*
  1643.              * Some of the subdirectories in the path may
  1644.              * not exist.  Try and create them, and if
  1645.              * successful, try to create the directory again.  
  1646.              * Make sure that if we don't successfully create 
  1647.              * subdirectories and then recreate the directory, 
  1648.              * we return the errno corresponding to the failed
  1649.              * mkdir for the directory, not any of the directories
  1650.              * in the path.
  1651.              */
  1652.             realErrno = errno;
  1653.             strcpy(pathname, destFile);
  1654.             if ((s = strrchr(pathname, '/')) != NULL) {
  1655.             *s = '\0';
  1656.             if (CreateDirectory(pathname) == 0) {
  1657.                 result = mkdir(destFile, 
  1658.                     (int) (srcAttr.st_mode & 0777));
  1659.             } else {
  1660.                 errno = realErrno;
  1661.             }
  1662.             }
  1663.             if (result != 0) {
  1664.             fprintf(stderr, 
  1665.                 "Couldn't create directory \"%s\": %s.\n",
  1666. d614 1
  1667. a614 2
  1668.             return 1;
  1669.             }
  1670. d869 1
  1671. a869 1
  1672. #ifndef ds3100
  1673. d904 1
  1674. a904 1
  1675. #ifndef ds3100
  1676. d937 4
  1677. a940 1
  1678.     case S_IFRLNK: {
  1679. d952 2
  1680. a953 2
  1681.         status = Fs_SymLink(targetName, destFile, 
  1682.         (srcAttrPtr->st_mode & S_IFMT) == S_IFRLNK);
  1683. d955 30
  1684. a984 4
  1685.         fprintf(stderr,
  1686.             "Couldn't create link at \"%s\": %s.\n",
  1687.             destFile, Stat_GetMsg(status));
  1688.         return 1;
  1689. d990 2
  1690. a992 1
  1691.         ReturnStatus    status;
  1692. d994 3
  1693. d998 1
  1694. a998 1
  1695.         status = Fs_GetAttributes(srcFile, FALSE, &attrs);
  1696. d1001 1
  1697. a1001 1
  1698.             srcFile, Stat_GetMsg(status));
  1699. d1004 1
  1700. d1010 5
  1701. a1014 1
  1702.         srcAttrPtr->st_mode & 0777);
  1703. d1017 1
  1704. a1017 1
  1705.             destFile, Stat_GetMsg(status));
  1706. d1027 1
  1707. d1034 1
  1708. d1133 3
  1709. d1137 1
  1710. d1219 5
  1711. d1227 2
  1712. a1228 1
  1713.     if (utimes(fileName, times) != 0) {
  1714. d1235 1
  1715. d1245 1
  1716. d1349 37
  1717. @
  1718.  
  1719.  
  1720. 1.30
  1721. log
  1722. @creates directories on target path if they don't exist and target is a
  1723. directory
  1724. @
  1725. text
  1726. @d18 1
  1727. a18 1
  1728. static char rcsid[] = "$Header: /sprite/src/cmds/update/RCS/update.c,v 1.29 92/01/27 22:22:40 jhh Exp Locker: jhh $ SPRITE (Berkeley)";
  1729. d544 1
  1730. a544 1
  1731.             fprintf(stderr, "Pruning:    %s < %s >\n", destFile,
  1732. @
  1733.  
  1734.  
  1735. 1.29
  1736. log
  1737. @added -p option
  1738. @
  1739. text
  1740. @d18 1
  1741. a18 1
  1742. static char rcsid[] = "$Header: /user6/jhh/src/cmds/update.new/RCS/update.c,v 1.25 90/08/27 11:32:50 shirriff Exp Locker: jhh $ SPRITE (Berkeley)";
  1743. d107 4
  1744. a110 1
  1745. static regexp *pruneArray[MAX_PRUNE]; /* Regular expressions to prune. */
  1746. d542 5
  1747. a546 2
  1748.         if (regexec(pruneArray[i], lastSlash)) {
  1749.         printf("Pruning:    %s\n", destFile);
  1750. d583 29
  1751. a611 2
  1752.         if (mkdir(destFile, (int) (srcAttr.st_mode & 0777)) != 0) {
  1753.             fprintf(stderr, "Couldn't create directory \"%s\": %s.\n",
  1754. d613 2
  1755. a614 1
  1756.             return 1;
  1757. d1266 2
  1758. a1267 1
  1759.     pruneArray[prune] = expPtr;
  1760. @
  1761.  
  1762.  
  1763. 1.28
  1764. log
  1765. @if the destination is a symbolic link and some of the directories
  1766. in the path don't exist then create them.  This is consistent with
  1767. what happens for a regular file.
  1768. @
  1769. text
  1770. @d18 1
  1771. a18 1
  1772. static char rcsid[] = "$Header: /sprite/src/cmds/update/RCS/update.c,v 1.27 91/11/12 18:57:33 rab Exp $ SPRITE (Berkeley)";
  1773. d36 1
  1774. d66 1
  1775. a72 1
  1776.     {OPT_FALSE, "c", (char *) &move, "Copy instead of move"},
  1777. d93 2
  1778. d105 4
  1779. d529 1
  1780. d531 14
  1781. d918 4
  1782. a921 30
  1783.         char pathname[MAXPATHLEN];
  1784.         char *s;
  1785.         int realStatus;
  1786.  
  1787.         /*
  1788.          * Some of the subdirectories in the path may
  1789.          * not exist.  Try and create them, and if
  1790.          * successful, try to open the file again.  Make sure
  1791.          * that if we don't successfully create subdirectories and
  1792.          * then redo the open, we return the errno corresponding
  1793.          * to the open, not the failed mkdir.
  1794.          */
  1795.  
  1796.         realStatus = status;
  1797.         strcpy(pathname, destFile);
  1798.         if ((s = strrchr(pathname, '/')) != NULL) {
  1799.             *s = '\0';
  1800.             if (CreateDirectory(pathname) == 0) {
  1801.             status = Fs_SymLink(targetName, destFile, 
  1802.                 (srcAttrPtr->st_mode & S_IFMT) == S_IFRLNK);
  1803.             } else {
  1804.             status = realStatus;
  1805.             }
  1806.         }
  1807.         if (status != SUCCESS) {
  1808.             fprintf(stderr,
  1809.                 "Couldn't create link at \"%s\": %s.\n",
  1810.                 destFile, Stat_GetMsg(status));
  1811.             return 1;
  1812.         }
  1813. d1191 69
  1814. @
  1815.  
  1816.  
  1817. 1.27
  1818. log
  1819. @Added a -c flag for copy.  This is added for compatibility with `install'
  1820. so update can be used with imake.
  1821. @
  1822. text
  1823. @d18 1
  1824. a18 1
  1825. static char rcsid[] = "$Header: /sprite/src/cmds/update/RCS/update.c,v 1.26 91/11/12 18:54:04 rab Exp Locker: rab $ SPRITE (Berkeley)";
  1826. d896 30
  1827. a925 4
  1828.         fprintf(stderr,
  1829.             "Couldn't create link at \"%s\": %s.\n",
  1830.             destFile, Stat_GetMsg(status));
  1831.         return 1;
  1832. @
  1833.  
  1834.  
  1835. 1.26
  1836. log
  1837. @*** empty log message ***
  1838. @
  1839. text
  1840. @d18 1
  1841. a18 1
  1842. static char rcsid[] = "$Header: /sprite/src/cmds/update/RCS/update.c,v 1.25 90/08/27 11:32:50 shirriff Exp Locker: rab $ SPRITE (Berkeley)";
  1843. d71 1
  1844. a71 1
  1845.     {OPT_FALE, "c", (char *) &move, "Copy instead of move"},
  1846. @
  1847.  
  1848.  
  1849. 1.25
  1850. log
  1851. @Added -n flag to ignore errors.
  1852. @
  1853. text
  1854. @d18 1
  1855. a18 1
  1856. static char rcsid[] = "$Header: /sprite/src/cmds/update/RCS/update.c,v 1.24 90/06/27 13:33:11 jhh Exp Locker: shirriff $ SPRITE (Berkeley)";
  1857. d71 1
  1858. @
  1859.  
  1860.  
  1861. 1.24
  1862. log
  1863. @creation of remote links was broken (created symbolic links instead)
  1864. @
  1865. text
  1866. @d18 1
  1867. a18 1
  1868. static char rcsid[] = "$Header: /sprite/src/cmds/update/RCS/update.c,v 1.23 90/02/28 22:12:16 jhh Exp $ SPRITE (Berkeley)";
  1869. d64 1
  1870. d80 1
  1871. d571 3
  1872. @
  1873.  
  1874.  
  1875. 1.23
  1876. log
  1877. @fixed bug in target file permissions
  1878. @
  1879. text
  1880. @d18 1
  1881. a18 1
  1882. static char rcsid[] = "$Header: /sprite/src/cmds/update/RCS/update.c,v 1.21 90/02/22 18:36:19 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  1883. d878 1
  1884. d887 3
  1885. a889 1
  1886.         if (symlink(targetName, destFile) != 0) {
  1887. d891 2
  1888. a892 2
  1889.             "Couldn't create symbolic link at \"%s\": %s.\n",
  1890.             destFile, strerror(errno));
  1891. @
  1892.  
  1893.  
  1894. 1.22
  1895. log
  1896. @update backup file only if target is old enough to be deemed stable.
  1897. @
  1898. text
  1899. @d1077 11
  1900. a1087 1
  1901.  
  1902. @
  1903.  
  1904.  
  1905. 1.21
  1906. log
  1907. @run ls -l on backup file if it exists and backup specified.  fork
  1908. and setuid to nobody first to make sure can do normal system() cmd
  1909. without big security hole.
  1910. @
  1911. text
  1912. @d18 1
  1913. a18 1
  1914. static char rcsid[] = "$Header: /sprite/src/cmds/update/RCS/update.c,v 1.20 90/02/22 17:39:09 jhh Exp Locker: douglis $ SPRITE (Berkeley)";
  1915. d50 1
  1916. d68 2
  1917. d264 7
  1918. d518 1
  1919. d694 2
  1920. a695 3
  1921.     if (stat(tmpFileName, &backupAttr) == 0) {
  1922.         char lsCmd[MAXPATHLEN + 7];
  1923.         int pid;
  1924. d697 4
  1925. a700 10
  1926.         fprintf(stderr,
  1927.             "File \"%s\" already exists.\nRemove this file or do not specify backup directory.\n",
  1928.             tmpFileName);
  1929.  
  1930.         pid = fork();
  1931.         if (pid < 0) {
  1932.         perror("fork");
  1933.         exit(1);
  1934.         } else if (pid > 0) {
  1935.         while(wait(0) > 0) {
  1936. d702 1
  1937. a702 10
  1938.         } else {
  1939.         if (setreuid(-1,-1) < 0) {
  1940.             perror("setreuid");
  1941.             exit(1);
  1942.         }
  1943.         (void)sprintf (lsCmd, "ls -l %s", tmpFileName);
  1944.         (void)system(lsCmd);
  1945.         (void)sprintf (lsCmd, "ls -l %s", destFile);
  1946.         (void)system(lsCmd);
  1947.         exit(0);
  1948. a703 1
  1949.         return 1;
  1950. d705 1
  1951. a705 2
  1952.  
  1953.     if (Copy(destFile, &destAttr, tmpFileName, 1) != 0) {
  1954. @
  1955.  
  1956.  
  1957. 1.20
  1958. log
  1959. @fixed symbolic link bug
  1960. @
  1961. text
  1962. @d18 1
  1963. a18 1
  1964. static char rcsid[] = "$Header: /sprite/src/cmds/update/RCS/update.c,v 1.19 90/02/15 14:49:43 douglis Exp $ SPRITE (Berkeley)";
  1965. d684 3
  1966. d688 1
  1967. a688 1
  1968.             "File \"%s\" already exists.  Remove this file or do not\nspecify backup directory.\n",
  1969. d690 19
  1970. @
  1971.  
  1972.  
  1973. 1.19
  1974. log
  1975. @check for existing backup file.
  1976. @
  1977. text
  1978. @d18 1
  1979. a18 1
  1980. static char rcsid[] = "$Header: /sprite/src/cmds/update/RCS/update.c,v 1.18 90/01/22 09:51:47 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  1981. d341 7
  1982. a347 1
  1983.         if (stat(argv[1], &srcAttr) != 0) {
  1984. @
  1985.  
  1986.  
  1987. 1.18
  1988. log
  1989. @ Make sure that if we don't successfully create subdirectories
  1990.  and then redo the open, we return the errno corresponding
  1991. to the open, not the failed mkdir.
  1992. @
  1993. text
  1994. @d18 1
  1995. a18 1
  1996. static char rcsid[] = "$Header: /sprite/src/cmds/update/RCS/update.c,v 1.17 90/01/22 09:45:54 douglis Exp Locker: douglis $ SPRITE (Berkeley)";
  1997. d491 1
  1998. a491 1
  1999.     struct stat srcAttr, destAttr;
  2000. d676 7
  2001. @
  2002.  
  2003.  
  2004. 1.17
  2005. log
  2006. @JHH changes for not stripping on ds3100
  2007. @
  2008. text
  2009. @d18 1
  2010. a18 1
  2011. static char rcsid[] = "$Header: /a/newcmds/update/RCS/update.c,v 1.16 89/10/02 19:26:25 rab Exp Locker: jhh $ SPRITE (Berkeley)";
  2012. d751 1
  2013. d756 4
  2014. a759 1
  2015.          * successful, try to open the file again.
  2016. d762 1
  2017. d769 2
  2018. @
  2019.  
  2020.  
  2021. 1.16
  2022. log
  2023. @Added code to create intermediate directories in a
  2024. path.
  2025. @
  2026. text
  2027. @d18 1
  2028. a18 1
  2029. static char rcsid[] = "$Header: /a/newcmds/update/RCS/update.c,v 1.15 89/06/19 14:30:42 jhh Exp Locker: rab $ SPRITE (Berkeley)";
  2030. d82 1
  2031. a82 1
  2032.     {OPT_TRUE, "s", (char *) &strip, "Strip destination"},
  2033. d142 5
  2034. a146 1
  2035.  
  2036. d772 1
  2037. d786 1
  2038. d807 1
  2039. d820 1
  2040. @
  2041.  
  2042.  
  2043. 1.15
  2044. log
  2045. @now does devices
  2046. @
  2047. text
  2048. @d18 2
  2049. a19 2
  2050. static char rcsid[] = "$Header: /a/newcmds/update/RCS/update.c,v 1.14 89/03/23 15:59:30 douglis Exp $ SPRITE (Berkeley)";
  2051. #endif not lint
  2052. d35 1
  2053. d47 16
  2054. a62 16
  2055. int strip = 0;
  2056. int move = 0;
  2057. char *backupDir = (char *)0;
  2058. char *modeString = (char *)0;
  2059. int newMode = -1;
  2060. char *ownerName = (char *)0;
  2061. int newOwner = -1;
  2062. int preserveOwnership = 0;
  2063. char *groupName = (char *)0;
  2064. int newGroup = -1;
  2065. int force = 0;
  2066. int noLinks = 0;
  2067. int copyLinks = 1;
  2068. int setTimes = 1;
  2069. int quietMode = 0;
  2070. int verifyMode = 0;
  2071. d64 1
  2072. a64 1
  2073. Option optionArray[] = {
  2074. d92 1
  2075. a92 1
  2076. int realUid;            /* The user id of the caller (which is not
  2077. d100 7
  2078. a106 4
  2079. extern int Update();
  2080. extern int UpdateDir();
  2081. extern int Copy();
  2082. extern void CheckGroup();
  2083. d124 1
  2084. a124 1
  2085.  
  2086. d288 1
  2087. d310 2
  2088. a311 2
  2089.                 "Couldn't create destination directory \"%s\": %s.\n",
  2090.                 destFile, strerror(errno));
  2091. d375 1
  2092. a375 1
  2093.     return 0;
  2094. d377 1
  2095. a377 1
  2096.     return 1;
  2097. d396 1
  2098. d424 1
  2099. a424 1
  2100. int
  2101. d451 1
  2102. a451 1
  2103.     charPtr = rindex(srcFile, '/');
  2104. d480 1
  2105. a480 1
  2106. int
  2107. d665 1
  2108. a665 1
  2109.     lastSlash = rindex(destFile, '/');
  2110. d704 1
  2111. a704 1
  2112. int
  2113. d745 19
  2114. a763 1
  2115.         fprintf(stderr, "Couldn't create \"%s\": %s.\n",
  2116. d765 2
  2117. a766 1
  2118.         return 1;
  2119. d926 1
  2120. a926 1
  2121. void
  2122. d972 1
  2123. a972 1
  2124. int
  2125. d1076 1
  2126. a1076 1
  2127.     
  2128. d1079 30
  2129. @
  2130.  
  2131.  
  2132. 1.14
  2133. log
  2134. @added special case check of "install foo bar" followed by "install
  2135. -l foo bar" causing confusing message claiming that foo is a regular
  2136. file when it's really a symbolic link.  
  2137. @
  2138. text
  2139. @d18 1
  2140. a18 1
  2141. static char rcsid[] = "$Header: /a/newcmds/update/RCS/update.c,v 1.13 89/02/02 15:57:59 brent Exp Locker: douglis $ SPRITE (Berkeley)";
  2142. d828 22
  2143. a849 3
  2144.         fprintf(stderr, "\"%s\" is a device; don't know how to update.\n",
  2145.             srcFile);
  2146.         return 1;
  2147. @
  2148.  
  2149.  
  2150. 1.13
  2151. log
  2152. @Fixed BUFSIZE to really be 8K
  2153. @
  2154. text
  2155. @d18 1
  2156. a18 1
  2157. static char rcsid[] = "$Header: /a/newcmds/update/RCS/update.c,v 1.12 88/12/28 11:31:31 ouster Exp $ SPRITE (Berkeley)";
  2158. d541 14
  2159. @
  2160.  
  2161.  
  2162. 1.12
  2163. log
  2164. @Don't preserve set-group-id bits (for now).
  2165. @
  2166. text
  2167. @d18 1
  2168. a18 1
  2169. static char rcsid[] = "$Header: /a/newcmds/update/RCS/update.c,v 1.11 88/12/28 11:22:04 ouster Exp Locker: ouster $ SPRITE (Berkeley)";
  2170. d695 1
  2171. a695 1
  2172. #define BUFSIZE 8196
  2173. @
  2174.  
  2175.  
  2176. 1.11
  2177. log
  2178. @Wasn't retaining set-user-id for backup copies.
  2179. @
  2180. text
  2181. @d18 1
  2182. a18 1
  2183. static char rcsid[] = "$Header: /a/newcmds/update/RCS/update.c,v 1.9 88/12/22 13:50:02 brent Exp $ SPRITE (Berkeley)";
  2184. d983 1
  2185. a983 1
  2186.     if ((attrPtr->st_mode & (S_ISUID|S_ISGID)) &&
  2187. d985 1
  2188. a985 1
  2189.         if (chmod(fileName, attrPtr->st_mode & 06777) != 0) {
  2190. d987 1
  2191. a987 1
  2192.             "Couldn't set set-user/group-id for \"%s\": %s.\n",
  2193. @
  2194.  
  2195.  
  2196. 1.10
  2197. log
  2198. @Preserve set-user-id whenever possible.
  2199. @
  2200. text
  2201. @d975 1
  2202. a975 1
  2203.     }
  2204. d977 14
  2205. a990 13
  2206.     /*
  2207.      * Preserve the set-user-id bit if a new mode wasn't given, and if
  2208.      * the set-user-id bit was set in the source file, and if the file's
  2209.      * new owner is the same as its previous owner.
  2210.      */
  2211.  
  2212.     if ((newMode < 0) && (attrPtr->st_mode & (S_ISUID|S_ISGID)) &&
  2213.         (preserveOwnership || (realUid == attrPtr->st_uid))) {
  2214.     if (chmod(fileName, attrPtr->st_mode & 06777) != 0) {
  2215.         fprintf(stderr,
  2216.             "Couldn't set set-user/group-id for \"%s\": %s.\n",
  2217.             fileName, strerror(errno));
  2218.         return 1;
  2219. @
  2220.  
  2221.  
  2222. 1.9
  2223. log
  2224. @Added -O option
  2225. @
  2226. text
  2227. @d18 1
  2228. a18 1
  2229. static char rcsid[] = "$Header: update.c,v 1.8 88/08/25 13:24:12 ouster Exp $ SPRITE (Berkeley)";
  2230. d930 1
  2231. a930 1
  2232.      * Preserve ownership if requested.
  2233. d934 1
  2234. a934 1
  2235.     if (chown(fileName, attrPtr->st_uid, -1) != 0) {
  2236. d973 16
  2237. @
  2238.  
  2239.  
  2240. 1.8
  2241. log
  2242. @Preserve times on backup files.  Also, try unlinking backup
  2243. files to avoid errors on open-for-create (if file is 444).
  2244. @
  2245. text
  2246. @d18 1
  2247. a18 1
  2248. static char rcsid[] = "$Header: update.c,v 1.7 88/08/23 15:03:01 douglis Exp $ SPRITE (Berkeley)";
  2249. d53 1
  2250. d77 2
  2251. d102 1
  2252. d140 2
  2253. a141 1
  2254.     if ((ownerName != (char *) 0) || (groupName != (char *) 0)) {
  2255. d155 19
  2256. d202 1
  2257. a202 20
  2258.  
  2259.         grPtr = getgrnam(groupName);
  2260.         if (grPtr == (struct group *) 0) {
  2261.         fprintf(stderr,
  2262.             "Couldn't find \"%s\" group to check owner change.\n",
  2263.             groupName);
  2264.         exit(1);
  2265.         }
  2266.         for (i = 0; ; i++) {
  2267.         if (grPtr->gr_mem[i] == NULL) {
  2268.             fprintf(stderr,
  2269.                 "Can't change owners: you're not in the \"%s\" group.\n",
  2270.                 groupName);
  2271.             exit(1);
  2272.         }
  2273.         if (strcmp(grPtr->gr_mem[i], userName) == 0) {
  2274.             break;
  2275.         }
  2276.         }
  2277.         endgrent();
  2278. d853 47
  2279. d928 12
  2280. @
  2281.  
  2282.  
  2283. 1.7
  2284. log
  2285. @update the advisory file type of the file being updated.
  2286. @
  2287. text
  2288. @d18 1
  2289. a18 1
  2290. static char rcsid[] = "$Header: update.c,v 1.6 88/08/23 14:34:43 douglis Exp $ SPRITE (Berkeley)";
  2291. d310 1
  2292. a310 1
  2293.         if (SetAttributes(destFile, &destAttr) != 0) {
  2294. d510 1
  2295. a510 1
  2296.         return Copy(srcFile, &srcAttr, destFile, 1);
  2297. d525 1
  2298. a525 1
  2299.         if (SetAttributes(destFile, &srcAttr) != 0) {
  2300. d617 1
  2301. a617 1
  2302.         if (Copy(srcFile, &srcAttr, destFile, 1) == 0) {
  2303. d648 1
  2304. a648 1
  2305.     if (Copy(destFile, &destAttr, tmpFileName, 0) != 0) {
  2306. d655 1
  2307. a655 1
  2308.     return Copy(srcFile, &srcAttr, destFile, 1);
  2309. d680 1
  2310. a680 1
  2311. Copy(srcFile, srcAttrPtr, destFile, setAttrs)
  2312. d685 4
  2313. a688 4
  2314.     int setAttrs;            /* Non-zero means set attributes
  2315.                      * of target file from command line;
  2316.                      * this is usually done, except for
  2317.                      * copies to backup directories. */
  2318. d716 1
  2319. d831 1
  2320. a831 1
  2321.     if (setAttrs && (SetAttributes(destFile, srcAttrPtr) != 0)) {
  2322. d863 1
  2323. a863 1
  2324. SetAttributes(fileName, attrPtr)
  2325. d868 5
  2326. d881 1
  2327. a881 1
  2328.     if (newGroup >= 0) {
  2329. d904 1
  2330. a904 1
  2331.     if (newMode >= 0) {
  2332. d917 1
  2333. a917 1
  2334.     if (setTimes) {
  2335. @
  2336.  
  2337.  
  2338. 1.6
  2339. log
  2340. @[This is being checked in for JKO].
  2341.  
  2342. changed copy to update attributes from command line only if not
  2343. copying to backup directory.  changed calls to printf to use fprintf.
  2344. @
  2345. text
  2346. @d18 1
  2347. a18 1
  2348. static char rcsid[] = "$Header: update.c,v 1.5 88/08/20 14:26:59 ouster Exp $ SPRITE (Berkeley)";
  2349. d921 11
  2350. @
  2351.  
  2352.  
  2353. 1.5
  2354. log
  2355. @Lint cleanup.
  2356. @
  2357. text
  2358. @d18 1
  2359. a18 1
  2360. static char rcsid[] = "$Header: update.c,v 1.4 88/08/20 10:45:24 ouster Exp $ SPRITE (Berkeley)";
  2361. d295 1
  2362. a295 1
  2363.         printf("Installing: %s\n", destFile);
  2364. d505 1
  2365. a505 1
  2366.         printf("Installing: %s\n", destFile);
  2367. d510 1
  2368. a510 1
  2369.         return Copy(srcFile, &srcAttr, destFile);
  2370. d517 1
  2371. a517 1
  2372.         printf("Installing: %s\n", destFile);
  2373. d598 1
  2374. a598 1
  2375.         printf("Updating: %s\n", destFile);
  2376. d617 1
  2377. a617 1
  2378.         if (Copy(srcFile, &srcAttr, destFile) == 0) {
  2379. d648 1
  2380. a648 1
  2381.     if (Copy(destFile, &destAttr, tmpFileName) != 0) {
  2382. d655 1
  2383. a655 1
  2384.     return Copy(srcFile, &srcAttr, destFile);
  2385. d680 1
  2386. a680 1
  2387. Copy(srcFile, srcAttrPtr, destFile)
  2388. d685 4
  2389. d830 1
  2390. a830 1
  2391.     if (SetAttributes(destFile, srcAttrPtr) != 0) {
  2392. d901 1
  2393. a901 1
  2394.             "Couldn't set permissions of \"%s\" to 0x%x: %s.\n",
  2395. @
  2396.  
  2397.  
  2398. 1.4
  2399. log
  2400. @When stripping, wasn't clearing struct exec fields.
  2401. @
  2402. text
  2403. @d18 1
  2404. a18 1
  2405. static char rcsid[] = "$Header: update.c,v 1.3 88/08/18 14:53:46 ouster Exp $ SPRITE (Berkeley)";
  2406. d37 6
  2407. a120 1
  2408.     char *srcFile;
  2409. a363 1
  2410.     done:
  2411. a418 1
  2412.     register int length;
  2413. d520 1
  2414. a520 1
  2415.         if (mkdir(destFile, srcAttr.st_mode & 0777) != 0) {
  2416. d730 1
  2417. a730 1
  2418.         lseek(srcID, 0, L_SET);
  2419. a864 1
  2420.     int group, owner, mode;
  2421. d872 1
  2422. a872 1
  2423.     if (chown(fileName, -1, group) != 0) {
  2424. @
  2425.  
  2426.  
  2427. 1.3
  2428. log
  2429. @First complete version installed now.  All known bugs fixed.
  2430. @
  2431. text
  2432. @d18 1
  2433. a18 1
  2434. static char rcsid[] = "$Header: update.c,v 1.2 88/08/08 18:39:22 ouster Exp $ SPRITE (Berkeley)";
  2435. d701 1
  2436. d725 1
  2437. d747 13
  2438. @
  2439.  
  2440.  
  2441. 1.2
  2442. log
  2443. @Working except for setting attributes correctly, and
  2444. for security checks.
  2445. @
  2446. text
  2447. @d18 1
  2448. a18 1
  2449. static char rcsid[] = "$Header: proto.c,v 1.2 88/03/11 08:39:08 ouster Exp $ SPRITE (Berkeley)";
  2450. d27 1
  2451. d37 1
  2452. a37 1
  2453.  * Variable and tables used to parse and identify switch values:
  2454. a49 1
  2455. int softErrors = 0;
  2456. d52 3
  2457. d60 1
  2458. a60 1
  2459.         "Force: always update, modify time stamps"},
  2460. a62 2
  2461.     {OPT_TRUE, "i", (char *) &softErrors,
  2462.         "Ignore errors while setting time stamps or owner"},
  2463. d70 2
  2464. d73 3
  2465. d79 8
  2466. d121 1
  2467. d124 1
  2468. a124 1
  2469.      * Suck up command line options.
  2470. d129 17
  2471. d154 41
  2472. d196 6
  2473. a201 1
  2474.     if (groupName != (char *)0) {
  2475. d209 23
  2476. d284 1
  2477. d286 1
  2478. a286 2
  2479.          * Create the destination directory, and set its owner and group
  2480.          * from the command line.
  2481. d288 3
  2482. a290 5
  2483.         if (mkdir(destFile, 0777) != 0) {
  2484.         fprintf(stderr,
  2485.             "Couldn't create destination directory \"%s\": %s.\n",
  2486.             destFile, strerror(errno));
  2487.         exit(1);
  2488. d292 16
  2489. a307 4
  2490.         if (stat(destFile, &destAttr) != 0) {
  2491.         fprintf(stderr, "Could stat \"%s\" after creating it: %s.\n",
  2492.             destFile, strerror(errno));
  2493.         exit(1);
  2494. a308 3
  2495.         if (SetAttributes(destFile, &destAttr) != 0) {
  2496.         exit(1);
  2497.         }
  2498. d354 1
  2499. d501 6
  2500. a506 1
  2501.         printf("Installing: %s\n", destFile);
  2502. d511 1
  2503. a511 1
  2504.          * the code below which recusively updates it.
  2505. d513 2
  2506. a514 5
  2507.         printf("Installing: %s\n", destFile);
  2508.         if (mkdir(destFile, 0777) != 0) {
  2509.         fprintf(stderr, "Couldn't create directory \"%s\": %s.\n",
  2510.             destFile, strerror(errno));
  2511.         return 1;
  2512. d516 9
  2513. a524 2
  2514.         if (SetAttributes(destFile, &srcAttr) != 0) {
  2515.         return(1);
  2516. d544 1
  2517. a544 1
  2518.     if (move && !strip) {
  2519. d581 1
  2520. a581 1
  2521.     if (move && (rmdir(srcFile) != 0)) {
  2522. d594 6
  2523. a599 1
  2524.     printf("Updating: %s\n", destFile);
  2525. a653 7
  2526.  
  2527.     if (srcAttr.st_mtime < destAttr.st_mtime) {
  2528.     fprintf(stderr,
  2529.         "Target file \"%s\" is newer than \"%s\";  not updating.\n",
  2530.         srcFile, destFile);
  2531.     return 1;
  2532.     }
  2533. d689 1
  2534. a689 1
  2535.     if (move && !strip) {
  2536. d708 2
  2537. a709 1
  2538.         destID = open(destFile, O_WRONLY|O_CREAT|O_TRUNC, 0);
  2539. d828 3
  2540. a830 1
  2541.  *    options that specify owner, group and new mode * Results:
  2542. d834 1
  2543. a834 1
  2544.  *    Times, owner, and group may get changed for fileName.
  2545. d845 1
  2546. d851 1
  2547. a851 1
  2548.      * Set owner and group.
  2549. a853 5
  2550.     owner = attrPtr->st_uid;
  2551.     if (newOwner >= 0) {
  2552.     owner = newOwner;
  2553.     }
  2554.     group = attrPtr->st_gid;
  2555. d855 3
  2556. a857 6
  2557.     group = newGroup;
  2558.     }
  2559.     if (chown(fileName, owner, group) != 0) {
  2560.     fprintf(stderr, "Couldn't set owner and group of \"%s\": %s.\n",
  2561.         fileName, strerror(errno));
  2562.     if (!softErrors) {
  2563. d863 9
  2564. d877 6
  2565. a882 4
  2566.     if ((attrPtr->st_mode & S_IFMT) != S_IFLNK) {
  2567.     mode = attrPtr->st_mode & 07777;
  2568.     if (newMode >= 0) {
  2569.         mode = newMode;
  2570. a883 7
  2571.     if (chmod(fileName, mode) != 0) {
  2572.         fprintf(stderr, "Couldn't set permissions of \"%s\": %s.\n",
  2573.             fileName, strerror(errno));
  2574.         if (!softErrors) {
  2575.         return 1;
  2576.         }
  2577.     }
  2578. d890 7
  2579. a896 7
  2580.     times[0].tv_usec = times[1].tv_usec = 0;
  2581.     times[0].tv_sec = attrPtr->st_atime;
  2582.     times[1].tv_sec = attrPtr->st_mtime;
  2583.     if (utimes(fileName, times) != 0) {
  2584.     fprintf(stderr, "Couldn't set times of \"%s\": %s.\n",
  2585.         fileName, strerror(errno));
  2586.     if (!softErrors) {
  2587. @
  2588.  
  2589.  
  2590. 1.1
  2591. log
  2592. @Initial revision
  2593. @
  2594. text
  2595. @d118 1
  2596. a118 1
  2597.         fprintf(stderr, "Unknown user \"%s\"\n", ownerName);
  2598. d127 1
  2599. a127 1
  2600.         fprintf(stderr, "Unknown group \"%s\"\n", ownerName);
  2601. d135 2
  2602. a136 1
  2603.         fprintf(stderr, "Bad mode value \"%s\"", modeString);
  2604. d155 1
  2605. a155 1
  2606.         fprintf(stderr, "No sources for \"%s\"\n", destFile);
  2607. d189 1
  2608. a189 1
  2609.             "Couldn't create destination directory \"%s\": %s\n",
  2610. d194 1
  2611. a194 1
  2612.         fprintf(stderr, "Could stat \"%s\" after creating it: %s\n",
  2613. d208 1
  2614. a208 1
  2615.     fprintf(stderr, "Couldn't access \"%s\": %s\n", destFile,
  2616. d215 1
  2617. a215 1
  2618.             fprintf(stderr, "Couldn't access \"%s\": %s\n", argv[1],
  2619. d382 1
  2620. a382 1
  2621.     fprintf(stderr, "Couldn't find \"%s\": %s\n",
  2622. d401 1
  2623. a401 1
  2624.         fprintf(stderr, "Couldn't create directory \"%s\": %s\n",
  2625. d412 3
  2626. a414 3
  2627.     fprintf(stderr,  "Type of %s (%s) differs from type of %s (%s)\n",
  2628.         srcFile, (srcAttr.st_mode & S_IFMT) >> 12,
  2629.         destFile, (destAttr.st_mode & S_IFMT) >> 12);
  2630. d418 4
  2631. d423 10
  2632. a436 3
  2633.     DIR *dirStream;
  2634.     struct direct *dirEntryPtr;
  2635.     int numErrors = 0;
  2636. d440 1
  2637. a440 1
  2638.         fprintf(stderr, "Can't read source directory \"%s\"\n",
  2639. d458 11
  2640. d487 1
  2641. a487 1
  2642.         fprintf(stderr, "Couldn't rename \"%s\" to \"%s\": %s\n",
  2643. d494 1
  2644. a494 1
  2645.                 "Couldn't remove renamed old version \"%s\": %s\n",
  2646. d501 1
  2647. a501 1
  2648.             "Couldn't restore original \"%s\":  see \"%s\"\n",
  2649. d524 1
  2650. a524 1
  2651.             "Couldn't copy \"%s\" to backup dir \"%s\"\n",
  2652. d534 1
  2653. a534 1
  2654.         "Target file \"%s\" is newer than \"%s\";  not updating\n",
  2655. d588 1
  2656. a588 1
  2657.         fprintf(stderr, "Couldn't open \"%s\": %s\n",
  2658. d594 1
  2659. a594 1
  2660.         fprintf(stderr, "Couldn't create \"%s\": %s\n",
  2661. d603 1
  2662. a603 1
  2663.                 "\"%s\" isn't a binary executable;  can't strip\n",
  2664. d621 1
  2665. a621 1
  2666.             fprintf(stderr, "Read error on \"%s\": %s\n",
  2667. d630 1
  2668. a630 1
  2669.             fprintf(stderr, "Write error on \"%s\": %s\n",
  2670. d644 1
  2671. a644 1
  2672.         fprintf(stderr, "Internal error:  Copy called with directory\n");
  2673. d654 1
  2674. a654 1
  2675.         fprintf(stderr, "Couldn't read value of link \"%s\": %s\n",
  2676. d661 1
  2677. a661 1
  2678.             "Couldn't create symbolic link at \"%s\": %s\n",
  2679. d669 1
  2680. a669 1
  2681.         fprintf(stderr, "\"%s\" is a device; don't know how to update\n",
  2682. d674 1
  2683. a674 1
  2684.         fprintf(stderr, "\"%s\" is a fifo; don't know how to update\n",
  2685. d680 1
  2686. a680 1
  2687.             "\"%s\" is a pseudo-device; don't know how to update\n",
  2688. d686 1
  2689. a686 1
  2690.             "\"%s\" has type 0x%x; don't know how to update\n",
  2691. d697 1
  2692. a697 1
  2693.             "Couldn't remove source file \"%s\" during move: %s\n",
  2694. d743 1
  2695. a743 1
  2696.     fprintf(stderr, "Couldn't set owner and group of \"%s\": %s\n",
  2697. d757 1
  2698. a757 1
  2699.     mode = attrPtr->st_mode & 0x3777;
  2700. d762 1
  2701. a762 1
  2702.         fprintf(stderr, "Couldn't set permissions of \"%s\": %s\n",
  2703. d778 1
  2704. a778 1
  2705.     fprintf(stderr, "Couldn't set times of \"%s\": %s\n",
  2706. @
  2707.